package com.aizuda.boot.modules.file.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/**
 * WPS文件转换工具类
 * 使用WPS API进行文档格式转换
 * 
 * @author system
 * @description WPS文件转换工具
 * @date 2025年01月01日
 */
@Component
@Slf4j
public class WpsConversionUtil {

    /**
     * WPS API配置 - 从配置文件注入
     */
    @Value("${wps.api.url}")
    private String wpsApiUrl;
    
    @Value("${wps.api.app-id}")
    private String appId;
    
    @Value("${wps.api.app-secret}")
    private String appSecret;
    
    /**
     * 转换超时时间（秒）
     */
    @Value("${wps.api.conversion-timeout:60}")
    private int conversionTimeout;
    
    private final OkHttpClient httpClient;

    public WpsConversionUtil() {
        this.httpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS) // 默认60秒，启动后会使用配置值
                .writeTimeout(30, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 将Word文档转换为PDF
     * 
     * @param fileUrl 文件下载URL地址
     * @param fileName 文件名（包含扩展名）
     * @return 转换后的PDF文件下载URL
     * @throws Exception 转换失败时抛出异常
     */
    public String convertWordToPdf(String fileUrl, String fileName) throws Exception {
        log.info("开始使用WPS API将Word转换为PDF，文件名: {}, URL: {}", fileName, fileUrl);
        
        if (StrUtil.isEmpty(fileUrl) || StrUtil.isEmpty(fileName)) {
            throw new IllegalArgumentException("文件URL和文件名不能为空");
        }
        

        
        // 构建请求参数 - 尝试不同的JSON格式
        String requestBodyStr;
        try {
            // 方法1：使用JSONObject（默认）
            JSONObject requestBody = new JSONObject();
            requestBody.put("url", fileUrl);
            requestBody.put("filename", fileName);
            requestBodyStr = requestBody.toString();
            

            
        } catch (Exception e) {
            // 方法2：手动构建JSON（备用方案）
            requestBodyStr = String.format("{\"url\":\"%s\",\"filename\":\"%s\"}", 
                    fileUrl.replace("\"", "\\\""), 
                    fileName.replace("\"", "\\\""));
            log.warn("JSONObject构建失败，使用手动构建: {}", requestBodyStr);
        }
        
        // 生成签名所需的头部信息
        String date = generateRFC1123Date();
        String contentMd5 = generateMD5(requestBodyStr);
        String contentType = "application/json";
        String authorization = generateAuthorization(contentMd5, contentType, date);
        

        
        // 构建HTTP请求
        // 尝试第一种方案：标准Content-Type
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), requestBodyStr);
        Request request = new Request.Builder()
                .url(wpsApiUrl)
                .post(body)
                .addHeader("Date", date)
                .addHeader("Content-Md5", contentMd5)
                .addHeader("Content-Type", contentType)
                .addHeader("Authorization", authorization)
                .build();
        
        // 发送请求（支持重试不同的Content-Type）
        try (Response response = httpClient.newCall(request).execute()) {
            String responseBody = response.body() != null ? response.body().string() : "";
            
            if (!response.isSuccessful()) {
                log.error("WPS转换API调用失败，状态码: {}, 响应: {}", response.code(), responseBody);
                
                // 如果是签名错误且使用的是基础Content-Type，尝试带charset的版本
                if (response.code() == 403 && responseBody.contains("InvalidSignature") && "application/json".equals(contentType)) {
                    log.info("尝试使用带charset的Content-Type重新签名");
                    return retryWithCharsetContentType(fileUrl, fileName);
                }
                
                throw new RuntimeException("WPS转换API调用失败，状态码: " + response.code() + ", 响应: " + responseBody);
            }
            
            // 解析响应
            JSONObject responseJson = JSONUtil.parseObj(responseBody);
            
            // 检查转换是否成功
            if (responseJson.containsKey("code") && !responseJson.getInt("code").equals(0)) {
                String errorMsg = responseJson.getStr("msg", "转换失败");
                log.error("WPS转换失败: {}", errorMsg);
                throw new RuntimeException("WPS转换失败: " + errorMsg);
            }
            
            // 解析响应 - WPS可能返回task_id（异步）或直接返回URL
            String result = responseJson.getStr("data");
            if (StrUtil.isEmpty(result)) {
                JSONObject data = responseJson.getJSONObject("data");
                if (data != null) {
                    result = data.getStr("url");
                    if (StrUtil.isEmpty(result)) {
                        result = data.toString(); // 可能整个data就是我们需要的
                    }
                }
            }
            
            if (StrUtil.isEmpty(result)) {
                log.error("WPS转换响应中未找到结果，响应: {}", responseBody);
                throw new RuntimeException("WPS转换响应中未找到结果");
            }
            
            // 检查是否返回的是task_id（异步模式）
            if (result.contains("task_id")) {
                // 解析task_id
                JSONObject taskInfo = JSONUtil.parseObj(result);
                String taskId = taskInfo.getStr("task_id");
                
                // 轮询查询任务状态直到完成
                return pollTaskStatus(taskId);
            } else {
                // 直接返回的是PDF URL
                return result;
            }
        }
    }
    
    /**
     * 生成RFC1123格式的当前时间
     */
    private String generateRFC1123Date() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH);
        dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
        return dateFormat.format(new Date());
    }
    
    /**
     * 生成字符串的MD5值
     */
    private String generateMD5(String input) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        for (byte b : hashBytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    
    /**
     * 生成WPS API的Authorization头
     */
    private String generateAuthorization(String contentMd5, String contentType, String date) throws Exception {
        // 根据WPS API文档：sha1( app_key + Content-Md5 + Content-Type + DATE)
        String stringToSign = appSecret + contentMd5 + contentType + date;
        
        // 使用SHA1算法，不是HmacSHA1
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
        byte[] hashBytes = sha1.digest(stringToSign.getBytes(StandardCharsets.UTF_8));
        
        StringBuilder sb = new StringBuilder();
        for (byte b : hashBytes) {
            sb.append(String.format("%02x", b));
        }
        
        String signature = sb.toString();
        
        return "WPS-2:" + appId + ":" + signature;
    }
    
    /**
     * 轮询查询任务状态直到转换完成
     */
    private String pollTaskStatus(String taskId) throws Exception {
        
        int maxRetries = 30; // 最多查询30次
        int retryInterval = 2000; // 每次间隔2秒
        
        for (int i = 0; i < maxRetries; i++) {
            try {
                // 构建查询URL
                String queryUrl = "https://solution.wps.cn/api/developer/v1/tasks/" + taskId;
                String queryPath = "/api/developer/v1/tasks/" + taskId;
                
                // 生成查询请求的签名（GET请求）
                String date = generateRFC1123Date();
                String contentMd5 = generateMD5(queryPath); // GET请求使用URI计算MD5
                String contentType = "application/json";
                String authorization = generateAuthorization(contentMd5, contentType, date);
                
                // 构建查询请求
                Request request = new Request.Builder()
                        .url(queryUrl)
                        .get()
                        .addHeader("Date", date)
                        .addHeader("Content-Md5", contentMd5)
                        .addHeader("Content-Type", contentType)
                        .addHeader("Authorization", authorization)
                        .build();
                
                // 发送查询请求
                try (Response response = httpClient.newCall(request).execute()) {
                    String responseBody = response.body() != null ? response.body().string() : "";
                    
                    if (!response.isSuccessful()) {
                        log.warn("查询任务状态失败，状态码: {}, 响应: {}", response.code(), responseBody);
                        if (i == maxRetries - 1) {
                            throw new RuntimeException("查询任务状态失败，状态码: " + response.code());
                        }
                        continue;
                    }
                    
                    // 解析查询结果
                    JSONObject queryResult = JSONUtil.parseObj(responseBody);
                    
                    if (queryResult.containsKey("code") && !queryResult.getInt("code").equals(0)) {
                        String errorMsg = queryResult.getStr("message", "查询失败");
                        log.warn("查询任务状态返回错误: {}", errorMsg);
                        if (i == maxRetries - 1) {
                            throw new RuntimeException("查询任务状态失败: " + errorMsg);
                        }
                        continue;
                    }
                    
                    JSONObject data = queryResult.getJSONObject("data");
                    if (data == null) {
                        log.warn("查询响应中未找到data字段");
                        if (i == maxRetries - 1) {
                            throw new RuntimeException("查询响应格式错误");
                        }
                        continue;
                    }
                    
                    String status = data.getStr("status");
                    int progress = data.getInt("progress", 0);
                    
                    if ("success".equals(status)) {
                        // 转换成功，获取PDF下载地址
                        JSONObject result = data.getJSONObject("result");
                        if (result != null) {
                            // 查找PDF下载地址
                            String pdfUrl = null;
                            
                            // 尝试从pdfs数组中获取
                            if (result.containsKey("pdfs")) {
                                Object pdfsObj = result.get("pdfs");
                                if (pdfsObj instanceof cn.hutool.json.JSONArray) {
                                    cn.hutool.json.JSONArray pdfs = (cn.hutool.json.JSONArray) pdfsObj;
                                    if (!pdfs.isEmpty()) {
                                        JSONObject firstPdf = pdfs.getJSONObject(0);
                                        pdfUrl = firstPdf.getStr("url");
                                    }
                                }
                            }
                            
                            if (StrUtil.isEmpty(pdfUrl)) {
                                log.error("转换成功但未找到PDF下载地址，响应: {}", responseBody);
                                throw new RuntimeException("转换成功但未找到PDF下载地址");
                            }
                            
                            return pdfUrl;
                        } else {
                            log.error("转换成功但result为空，响应: {}", responseBody);
                            throw new RuntimeException("转换成功但结果为空");
                        }
                    } else if ("failed".equals(status) || "failure".equals(status)) {
                        // 处理失败状态 - WPS可能返回"failed"或"failure"
                        String message = data.getStr("message", "转换失败");
                        if (StrUtil.isEmpty(message)) {
                            message = data.getStr("msg", "转换失败");
                        }
                        
                        log.error("WPS转换失败: {}", message);
                        throw new RuntimeException("WPS转换失败: " + message);
                    } else if ("processing".equals(status) || "pending".equals(status) || StrUtil.isEmpty(status)) {
                        // 还在处理中，继续等待
                        Thread.sleep(retryInterval);
                    } else {
                        // 未知状态，继续等待
                        Thread.sleep(retryInterval);
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("等待转换完成时被中断", e);
            } catch (RuntimeException e) {
                // 如果是转换失败的异常，直接抛出，不要重试
                if (e.getMessage().contains("WPS转换失败")) {
                    throw e;
                }
                
                if (i == maxRetries - 1) {
                    throw e;
                }
                try {
                    Thread.sleep(retryInterval);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("等待重试时被中断", ie);
                }
            } catch (Exception e) {
                if (i == maxRetries - 1) {
                    throw e;
                }
                try {
                    Thread.sleep(retryInterval);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("等待重试时被中断", ie);
                }
            }
        }
        
        throw new RuntimeException("WPS转换超时，超过最大重试次数");
    }
    

    
    /**
     * 使用带charset的Content-Type重试转换
     */
    private String retryWithCharsetContentType(String fileUrl, String fileName) throws Exception {
        // 构建请求参数
        JSONObject requestBody = new JSONObject();
        requestBody.put("url", fileUrl);
        requestBody.put("filename", fileName);
        String requestBodyStr = requestBody.toString();
        
        // 生成签名所需的头部信息 - 使用带charset的Content-Type
        String date = generateRFC1123Date();
        String contentMd5 = generateMD5(requestBodyStr);
        String contentTypeWithCharset = "application/json; charset=utf-8";
        String authorization = generateAuthorization(contentMd5, contentTypeWithCharset, date);
        
        // 构建HTTP请求
        RequestBody body = RequestBody.create(MediaType.parse(contentTypeWithCharset), requestBodyStr);
        Request request = new Request.Builder()
                .url(wpsApiUrl)
                .post(body)
                .addHeader("Date", date)
                .addHeader("Content-Md5", contentMd5)
                .addHeader("Content-Type", contentTypeWithCharset)
                .addHeader("Authorization", authorization)
                .build();
        
        // 发送重试请求
        try (Response response = httpClient.newCall(request).execute()) {
            String responseBody = response.body() != null ? response.body().string() : "";
            
            if (!response.isSuccessful()) {
                log.error("WPS转换API重试也失败，状态码: {}, 响应: {}", response.code(), responseBody);
                throw new RuntimeException("WPS转换API重试失败，状态码: " + response.code() + ", 响应: " + responseBody);
            }
            
            // 解析响应
            JSONObject responseJson = JSONUtil.parseObj(responseBody);
            
            // 检查转换是否成功
            if (responseJson.containsKey("code") && !responseJson.getInt("code").equals(0)) {
                String errorMsg = responseJson.getStr("msg", "转换失败");
                log.error("WPS转换重试失败: {}", errorMsg);
                throw new RuntimeException("WPS转换重试失败: " + errorMsg);
            }
            
            // 解析重试响应 - 与主方法保持一致
            String result = responseJson.getStr("data");
            if (StrUtil.isEmpty(result)) {
                JSONObject data = responseJson.getJSONObject("data");
                if (data != null) {
                    result = data.getStr("url");
                    if (StrUtil.isEmpty(result)) {
                        result = data.toString();
                    }
                }
            }
            
            if (StrUtil.isEmpty(result)) {
                log.error("WPS转换重试响应中未找到结果，响应: {}", responseBody);
                throw new RuntimeException("WPS转换重试响应中未找到结果");
            }
            
            // 检查是否返回的是task_id（异步模式）
            if (result.contains("task_id")) {
                // 解析task_id
                JSONObject taskInfo = JSONUtil.parseObj(result);
                String taskId = taskInfo.getStr("task_id");
                
                // 轮询查询任务状态直到完成
                return pollTaskStatus(taskId);
            } else {
                // 直接返回的是PDF URL
                return result;
            }
        }
    }
    
    /**
     * 检查WPS转换服务是否可用
     */
    public boolean isWpsServiceAvailable() {
        try {
            // 发送一个简单的测试请求来检查服务可用性
            Request request = new Request.Builder()
                    .url(wpsApiUrl)
                    .head() // 使用HEAD请求避免实际转换
                    .build();
            
            try (Response response = httpClient.newCall(request).execute()) {
                // 只要能连接到服务就认为可用，具体的错误会在实际转换时处理
                return true;
            }
        } catch (Exception e) {
            log.warn("WPS服务可用性检查失败", e);
            return false;
        }
    }
    
    /**
     * 下载转换后的PDF文件
     */
    public byte[] downloadPdfFile(String pdfUrl) throws Exception {
        
        Request request = new Request.Builder()
                .url(pdfUrl)
                .get()
                .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new RuntimeException("下载PDF文件失败，状态码: " + response.code());
            }
            
            ResponseBody responseBody = response.body();
            if (responseBody == null) {
                throw new RuntimeException("PDF文件内容为空");
            }
            
            byte[] pdfData = responseBody.bytes();
            return pdfData;
        }
    }
    

}